home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / util / Mac F2C 1.3.sit / Mac F2C 1.3 / Mac F2C Libraries / libI77 Sources / DoMultiTask.c < prev    next >
C/C++ Source or Header  |  1995-09-16  |  12KB  |  478 lines

  1.  
  2. /****************************************************************************
  3. *                                                                            *
  4. *    This code implements a simple but flexible function    that can be            *
  5. *    called to add multitasking to Fortran code ported to the Macintosh        *
  6. *    using Mac F2C and the MetroWerks, THINK, or    Symantec C/C++ compilers.    *
  7. *                                                                            *
  8. *    This code is based extensively on code provided by:                        *
  9. *                                                                            *
  10. *        Mel    Martinez                                                        *
  11. *        The    Johns Hopkins University                                        *
  12. *        Dept. of Physics                                                    *
  13. *        mem@jhu.edu                                                            *
  14. *                                                                            *
  15. *    However, any and all bugs present are my responsiblity.                    * 
  16. *        IMT    16Sep95                                                            *
  17. *                                                                            *
  18. ****************************************************************************/
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25. /***************************************************************************
  26.  
  27.     Metrowerks CodeWarrior version
  28.     ******************************
  29.  
  30.     The approach is simple.  At program startup, F2Cmain() calls InitMultiTask()
  31.     which set up a counter that keeps track of the ticks elapsed.   It also 
  32.     initializes the spinning cursors (if the required resource is present; 
  33.     otherwise it fails without impacting anything). 
  34.  
  35.     Then whenever you call the domultitask_ (or DoMultiTask) function, it checks
  36.     if enough ticks have elapsed.  If so it calls WNE and spins the cursor.  If
  37.     WNE returns an event, it is passed to the SIOUX console to handle.
  38.  
  39.     At program completion, F2Cmain() calls EndMultiTask() which cleans up.
  40.  
  41. ***************************************************************************/
  42.     
  43. #ifdef CW_F2C
  44.  
  45. #include <Events.h>
  46. #include <OSEvents.h>
  47. #include <OSUtils.h>
  48. #include <Quickdraw.h>
  49. #include <ToolUtils.h>
  50. #include <Resources.h>
  51.  
  52. #include <SIOUX.h>   
  53.  
  54.  
  55. /* Declare f2c library function used to recover from exception exits & aborts */
  56. void sig_die( char*, int );
  57.  
  58. /* Cursor related functions */
  59. Boolean InitAnimatedCursors( short acurID );
  60. void ReleaseAnimatedCursors( void );
  61. void SpinMyCursor( void );
  62.  
  63. /* Private globals */
  64. static long            gNextCheck;            /* Used to hold tick counts */
  65. static long            gTickSlice = 2;        /* 1/30th second in ticks (each tick = 1/60th sec) */
  66.  
  67.  
  68. /**********************************************************************
  69. *                                                                      *
  70. *    The    slice parameter above is the control that sets exactly           *
  71. *    how often the program will actually    call WaitNextEvent.              *
  72. *                                                                      *
  73. *        - The above    value is the recommended rate for assuring          *
  74. *          that user    interaction    is not affected    (even QuickTime          *
  75. *          movies should    still run fine in the foreground).              *
  76. *                                                                      *
  77. *        - If you want to be    less friendly and use more CPU              *
  78. *          time,    increase this number.                                  *
  79. *                                                                      *
  80. **********************************************************************/
  81.  
  82.  
  83.  
  84.  
  85. /*
  86.     Use this in F2Cmain.c to initialize the multi-tasking code
  87. */
  88.  
  89. void InitMultiTask( long sliceInTicks ) 
  90. {
  91.     if ( sliceInTicks > 0 )
  92.         gTickSlice = sliceInTicks;    
  93.  
  94.     InitAnimatedCursors( 128 );
  95.     
  96.     /* Start the tick count */
  97.     gNextCheck = TickCount() + gTickSlice;
  98. }
  99.  
  100.  
  101.  
  102.  
  103.  
  104. /*
  105.     Use this in F2Cmain.c to close-out the multi-tasking code
  106. */
  107.  
  108. void EndMultiTask( void )
  109. {
  110.     ReleaseAnimatedCursors();
  111. }
  112.  
  113.  
  114.  
  115.  
  116.  
  117. /*
  118.     Get to this call in your FORTRAN code by inserting CALL DOMULTITASK( sleepTime )
  119. */
  120.  
  121. int domultitask_( long *sleepTime )
  122. {
  123.     extern Boolean SIOUXQuitting;
  124.     EventRecord myEvent;
  125.  
  126.      if( TickCount() > gNextCheck )                       /* Time to check for events again? */
  127.     {
  128.          if( WaitNextEvent( everyEvent, &myEvent, *sleepTime, NULL ) )
  129.           {
  130.               /* Restore arrow while we're handling a real event */
  131.               SetCursor( &(qd.arrow) );
  132.               
  133.               /* Need to do something with the event if we got one */
  134.             /* Add additional event handling code here if you need it */
  135.             SIOUXHandleOneEvent( &myEvent );      
  136.             if( SIOUXQuitting )
  137.                 sig_die("User interrupt; execution stopped", 1);        /* Graceful quit */
  138.          }
  139.         SpinMyCursor();                                 /* Spin the cursor */
  140.         gNextCheck = TickCount() + gTickSlice;            /* Reset the tick count */
  141.     }
  142.     
  143.     return 1;
  144. }
  145.  
  146.  
  147.  
  148. /* 
  149.     Add this function so users can add DoMultiTask(n) calls to the
  150.     C output from Mac F2C if they prefer, instead of inserting
  151.     CALL DOMULTITASK(n) in the FORTRAN code 
  152. */
  153.  
  154. void DoMultiTask( long sleepTime )
  155. {
  156.     domultitask_( &sleepTime );
  157. }
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164. /********************
  165.  
  166.     Following are functions related to making the cursors spin.
  167.  
  168.     Wrote my own instead of using the InitCursors()/SpinCursor()/RotateCursor()
  169.     package because it is an incomplete port from the MPW environment found in
  170.     the MPW ToolLibs libraries and linking against them in the incorrect order
  171.     can give rise to subtle inconsistencies.  A likely source of problems for users.
  172.  
  173. ********************/
  174.  
  175.  
  176.  
  177. typedef struct        /* My version of the structure of an 'acur' resource */
  178. {
  179.     short numberOfFrames;            /* Number of cursors to animate */
  180.     short whichFrame;                /* Current frame number    */
  181.     CursHandle frame[];                /* Pointer to the first cursor */
  182. } acur, *acurPtr, **acurHandle;
  183.  
  184. static acurHandle gCursorList;        /* The cursor list */
  185.  
  186.  
  187.  
  188. /* 
  189.     Try to get the acur record and the cursor list for acurID, 
  190.     returning 1 (= TRUE) if everything goes as planned. 
  191. */
  192.  
  193. Boolean InitAnimatedCursors( short acurID )
  194. {
  195.     register short i = 0;
  196.     register short cursID;
  197.     Boolean noErrFlag = 0;
  198.  
  199.     if ( gCursorList = (acurHandle) GetResource( 'acur',acurID ) ) 
  200.     {
  201.         /* Got it! */ 
  202.         noErrFlag = 1;
  203.         while ( (i < (*gCursorList)->numberOfFrames) && noErrFlag ) 
  204.         {
  205.             /* The id of the cursor is stored in the high word of the frame handle */ 
  206.             cursID = (short) HiWord( (long) (*gCursorList)->frame[i] );
  207.             (*gCursorList)->frame[i] = GetCursor( cursID );
  208.             if ( (*gCursorList)->frame[i] )
  209.                 i++;                                /* Get the next one */
  210.             else
  211.                 noErrFlag = 0;                        /* Couldn't find the cursor */
  212.         }
  213.     }
  214.     
  215.     if ( noErrFlag ) 
  216.     {
  217.         (*gCursorList)->whichFrame = 0;
  218.     }
  219.     else
  220.     {
  221.         /* Free up memory we won't use */
  222.         if ( gCursorList )
  223.         {
  224.             (*gCursorList)->numberOfFrames = i;        /* These are all we managed to get */
  225.             ReleaseAnimatedCursors();
  226.         }
  227.         gCursorList = NULL;
  228.     }
  229.     
  230.     return noErrFlag;
  231. }
  232.  
  233.  
  234.  
  235.  
  236. /* 
  237.     Free up the storage used by the current animated cursor 
  238.     and all of its frames 
  239. */
  240.  
  241. void ReleaseAnimatedCursors( void )
  242. {
  243.     short i;
  244.     if ( gCursorList )
  245.     {
  246.         for ( i = 0; i< (*gCursorList)->numberOfFrames; i++ )
  247.             ReleaseResource( (Handle) (*gCursorList)->frame[i] );
  248.         ReleaseResource( (Handle) gCursorList );
  249.     }
  250. }
  251.  
  252.  
  253.  
  254. /*     
  255.     Display the next frame in the sequence. 
  256. */
  257.  
  258. void SpinMyCursor( void )
  259. {
  260.     if ( gCursorList )
  261.     {
  262.         /* Grab the frame, increment (and reset, if necessary) the count, */
  263.         /* and display the new cursor */
  264.         SetCursor( *((*gCursorList)->frame[(*gCursorList)->whichFrame++]) );
  265.         if( (*gCursorList)->whichFrame == (*gCursorList)->numberOfFrames )
  266.             (*gCursorList)->whichFrame = 0;
  267.     }
  268. }
  269.  
  270.  
  271. #endif    /* CW_F2C */
  272.  
  273.  
  274.  
  275.  
  276.  
  277.  
  278. /***************************************************************************
  279.  
  280.     THINK (68K) and Symantec (PPC) version
  281.     **************************************
  282.  
  283.     The THINK console does not have to pass an event back to it (i.e., an 
  284.     equivalent of CW's SIOUXHandleOneEvent function).  So we can't call
  285.     WNE directly because if we get an event there' no way to hand it back 
  286.     to the console (sorry, setting the event mask in WNE to 0x0000 or 0x0001
  287.     to get only null events doesn't work--nice idea though).  
  288.  
  289.     So instead have to do the following:
  290.     (a) Set stdin to raw, unbuffered mode.
  291.     (b) Call getchar() which forces the console to call WNE for us.  
  292.         Because we are in raw mode, getchar() returns immediately even if
  293.         the user doesn't type anything.
  294.     (c) Set stdin back to buffered mode.
  295.  
  296.     Alas, changing the mode of stdin is very slow.  So instead of implementing
  297.     the above directly, we make raw/unbuffer the 'default' mode on stdin so 
  298.     we don't have to change modes just to call WNE (via getchar).  And we
  299.     compensate by changing back to buffered mode prior to doing any input on 
  300.     stdio (and then restoring raw/unbuffered mode).  (InitMultiTask() and
  301.     EndMultiTask() are used to adjust the default mode on stdio).
  302.  
  303.     Luckily for this plan, the f2c library bottlenecks all input operations
  304.     through fread(), getc(), and ungetc().  Our replacements for these are
  305.     defined below.  They simply pass the call through to the 'real' versions 
  306.     of the above functions, changing modes appropriately if the file used 
  307.     for I/O is stdin.
  308.  
  309.     My versions of these functions are patched into the f2c library code
  310.     via macros in TPM_I.h and TPM_F.h.
  311.  
  312.     Many thanks to Phil Shapiro of Symantec for suggesting this approach.
  313.  
  314.     Also, there is no cursor spinning in this TPM/SPM version because the 
  315.     console updates the cursor on every opportunity, so all we do is end 
  316.     up fighting the console for control of the cursor's appearance.
  317.  
  318. ***************************************************************************/
  319.     
  320.  
  321. #if defined(TPM_F2C) || defined(SPM_F2C)
  322.  
  323. /* Undefine some #defines that come from TPM_I.h and SPM_I.h that we don't want here */
  324. #undef fread
  325. #undef __getc
  326. #undef ungetc
  327. #include <stdio.h>            /* We want the original unsubstituted versions */
  328.  
  329. #include <Events.h>
  330. #include <OSEvents.h>
  331. #include <OSUtils.h>
  332.  
  333. #include <console.h>
  334.  
  335. /* Private globals */
  336. static long            gNextCheck = 0;        /* Used to hold tick counts */
  337. static long            gTickSlice = 2;        /* 1/30th second in ticks (each tick = 1/60th sec) */
  338.  
  339. /**********************************************************************
  340. *                                                                      *
  341. *    The    slice parameter above is the control that sets exactly           *
  342. *    how often the program will actually    call WaitNextEvent.              *
  343. *                                                                      *
  344. *        - The above    value is the recommended rate for assuring          *
  345. *          that user    interaction    is not affected    (even QuickTime          *
  346. *          movies should    still run fine in the foreground).              *
  347. *                                                                      *
  348. *        - If you want to be    less friendly and use more CPU              *
  349. *          time,    increase this number.                                  *
  350. *                                                                      *
  351. **********************************************************************/
  352.  
  353.  
  354.  
  355.  
  356. /*
  357.     This is used in F2Cmain.c to initialize the multi-tasking code
  358. */
  359.  
  360. void InitMultiTask( long sliceInTicks ) 
  361. {
  362.     if ( sliceInTicks > 0 )
  363.         gTickSlice = sliceInTicks;    
  364.     
  365.     /* Set console so we can interogate for input (to trigger WNE) without waiting for input */
  366.     csetmode( C_RAW, stdin );
  367.  
  368.     /* Start the tick count */
  369.     gNextCheck = TickCount() + gTickSlice;
  370. }
  371.  
  372.  
  373.  
  374.  
  375.  
  376. /*
  377.     This is used in F2Cmain.c to close-out the multi-tasking code
  378. */
  379.  
  380. void EndMultiTask( void )
  381. {
  382.     csetmode(C_ECHO, stdin);     /* Restore standard, buffered mode (not really required :) */
  383. }
  384.  
  385.  
  386.  
  387.  
  388.  
  389. /*
  390.     Get to this call in your FORTRAN code by inserting CALL DOMULTITASK( sleepTime )
  391. */
  392.  
  393. int domultitask_( long *sleepTime )
  394. {
  395.      if( TickCount() > gNextCheck )                   /* Time to check for events again? */
  396.     {
  397.         getchar();                                   /* poll for char to have console call WNE */
  398.         gNextCheck = TickCount() + gTickSlice;        /* Reset the tick count */
  399.     }
  400.     return 1;
  401. }
  402.  
  403.  
  404.  
  405. /* 
  406.     Add this function so users can add DoMultiTask(n) calls to the
  407.     C output from Mac F2C if they prefer, instead of inserting
  408.     CALL DOMULTITASK(n) in the FORTRAN code 
  409. */
  410.  
  411. void DoMultiTask( long sleepTime )
  412. {
  413.     domultitask_( &sleepTime );
  414. }
  415.  
  416.  
  417.  
  418. /*
  419.     Because now stdin is (by default) in raw mode, must re-set it before reading
  420.     from it.  These replacement functions cover all the input functions used 
  421.     in the f2c libs.  #defines in TPM_F2C and SPM_F2C ensure that these are called
  422.     instead of their originals
  423. */
  424.  
  425.  
  426. size_t F2C_fread( void *ptr, size_t size, size_t n, FILE *f )
  427. {
  428.     size_t  nr;
  429.     if ( f == stdin )
  430.     {
  431.         csetmode(C_ECHO, stdin); 
  432.         nr = fread( ptr, size, n, f );
  433.         csetmode(C_RAW, stdin);
  434.     }
  435.     else
  436.         nr = fread( ptr, size, n, f );
  437.  
  438.     return  nr;
  439. }
  440.  
  441.  
  442. int F2C_getc( FILE * f)
  443. {
  444.     int i;
  445.     if ( f == stdin )
  446.     {
  447.         csetmode(C_ECHO, stdin); 
  448.         i = __getc( f );
  449.         csetmode(C_RAW, stdin);
  450.     }
  451.     else
  452.         i = __getc( f );
  453.  
  454.     return  i;
  455. }
  456.  
  457.  
  458. int F2C_ungetc( int c, FILE *f )
  459. {
  460.     int i;
  461.     if ( f == stdin )
  462.     {
  463.         csetmode(C_ECHO, stdin); 
  464.         i = ungetc( c, f );
  465.         csetmode(C_RAW, stdin);
  466.     }
  467.     else
  468.         i = ungetc( c, f );
  469.  
  470.     return  i;
  471. }
  472.     
  473.  
  474. #endif    /* TPM_F2C or SPM_F2C */
  475.  
  476.  
  477.  
  478.